/**
 * idastar.c
 *
 * @author Shane Crumlish
 */

#include <stdio.h>
#include <math.h>
#include <stdbool.h>
#include <limits.h>
#include "cube.h"
#include "cubeLinkedList.h"
#include "cubeIO.h"
#include "idastar.h"

// Get heuristic from heuristic table
uint8_t heuristic_function(Cube cube, uint8_t *htables[3])
{

    uint8_t distances[3];

    getCubeHeuristics(htables, cube, distances);

    uint8_t i, heuristic = 0;

    //Get max of the three values
    for (i = 0; i < 3; ++i)
    {
        heuristic = (heuristic < distances[i]) ? distances[i] : heuristic;
    }

    return heuristic;
}

// function for goal test
bool is_goal(Cube cube)
{
    if (equalCubes(&cube, &UNIT_CUBE))
        return true;
    else
        return false;
}

// 'F' stands foud 'FOUND', 'N' for 'NOT FOUND'
//TODO Probably replace this with bool
char ida_star(Cube root, uint8_t *htables[3])
{
    char path[61] =
    { 0 };

    int bound = heuristic_function(root, htables);

    while (true)
    {
        int t = search(root, 0, bound, path, htables);

        if (t == 0)
        {
            //TODO reduce this
            printf("Soln: %s\n", path);
            return 'F';
        }
        if (t == INT_MAX)
            return 'N';
        bound = t;
    }
}

int search(Cube cube, int g, int bound, char path[61], uint8_t *htables[3])
{
    // order of permuteAll is top, bottom, left, right, front, back
    static const char faces[6] =
    { 'W', 'Y', 'G', 'B', 'R', 'O' };

    Cube successorsArray[6];
    int f = g + heuristic_function(cube, htables);
    if (is_goal(cube))
        return 0;
    if (f > bound)
        return f;

    int min = INT_MAX;

    // get all 6 permutations of a cube, stored in succeessorsArray
    permuteAll(cube, successorsArray);
    int successor;
    for (successor = 0; successor < 6; ++successor)
    {
        int t = search(successorsArray[successor], g + 1, bound, path, htables);
        if (t == 0)
        {
            path[g] = faces[successor];
            return 0;
        }
        if (t < min)
            min = t;
    }

    return min;
}
